//
//  JFMacro.h
//  AWBase
//
//  Created by Alan Wang on 2018/6/30.
//  Copyright © 2018年 Alan Wang. All rights reserved.
//


#import <objc/runtime.h>


#define AWKEY_WINDOW [[UIApplication sharedApplication]keyWindow]
//获取屏幕尺寸
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
#define AWSCREEN_WIDTH ([[UIScreen mainScreen] respondsToSelector:@selector(nativeBounds)]?[UIScreen mainScreen].nativeBounds.size.width/[UIScreen mainScreen].nativeScale:[UIScreen mainScreen].bounds.size.width)
#define AWSCREENH_HEIGHT ([[UIScreen mainScreen] respondsToSelector:@selector(nativeBounds)]?[UIScreen mainScreen].nativeBounds.size.height/[UIScreen mainScreen].nativeScale:[UIScreen mainScreen].bounds.size.height)
#define AWSCREEN_SIZE ([[UIScreen mainScreen] respondsToSelector:@selector(nativeBounds)]?CGSizeMake([UIScreen mainScreen].nativeBounds.size.width/[UIScreen mainScreen].nativeScale,[UIScreen mainScreen].nativeBounds.size.height/[UIScreen mainScreen].nativeScale):[UIScreen mainScreen].bounds.size)
#define TABBAR_HEIGHT 49
#else
#define AWSCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define AWSCREENH_HEIGHT [UIScreen mainScreen].bounds.size.height
#define AWSCREEN_SIZE [UIScreen mainScreen].bounds.size
#define TABBAR_HEIGHT 49
#endif

#define SCREEN_WIDTH AWSCREEN_WIDTH
#define SCREEN_HEIGHT AWSCREENH_HEIGHT


#ifdef DEBUG
#define NSLog(...) NSLog(__VA_ARGS__)
#else
#define NSLog(...) {}
#endif

//日志
//#ifdef DEBUG
//#define AWLog(...) NSLog(@"%s 第%d行 \n %@\n\n",__func__,__LINE__,[[NSString stringWithFormat:__VA_ARGS__] UTF8String])
//#else
//#define AWLog(...)
//#endif


#ifdef DEBUG
//调试状态
#define FilePathNameString [NSString stringWithFormat:@"%s", __FILE__].lastPathComponent
#define AWLog(...) printf("%s 第%d行: %s\n\n",[FilePathNameString UTF8String] ,__LINE__, [[NSString stringWithFormat:__VA_ARGS__] UTF8String]);
#else
//发布状态
#define AWLog(...)
#endif



//GCD - 一次性执行
#define AWDISPATCH_ONCE_BLOCK(onceBlock) static dispatch_once_t onceToken; dispatch_once(&onceToken, onceBlock);
//GCD - 异步主线程
#define AWDISPATCH_MAIN_THREAD(mainQueueBlock) dispatch_async(dispatch_get_main_queue(), mainQueueBlock);
//GCD - 开启异步线程
#define AWDISPATCH_GLOBAL_QUEUE_DEFAULT(globalQueueBlock) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), globalQueueBlock);

//主线程同步队列
#define AWDispatch_main_sync_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_sync(dispatch_get_main_queue(), block);\
}
//主线程异步队列
#define AWDispatch_main_async_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}

//强弱引用
#define AWWeakSelf(type)  __weak typeof(type) weak##type = type;
#define AWStrongSelf(type)  __strong typeof(type) strongself = type;

#define WeakSelf(type)  __weak typeof(type) weakSelf = type;
#define StrongSelf(type)  __strong typeof(type) strongSelf = type;

#define WEAKSELF WeakSelf(self)
#define STRONGSELF StrongSelf(self)





#define TRYHONE_CODER_DECODER()     \
\
- (id)initWithCoder:(NSCoder *)coder    \
{   \
NSLog(@"%s",__func__);  \
Class cls = [self class];   \
while (cls != [NSObject class]) {   \
/*判断是自身类还是父类*/    \
BOOL bIsSelfClass = (cls == [self class]);  \
unsigned int iVarCount = 0; \
unsigned int propVarCount = 0;  \
unsigned int sharedVarCount = 0;    \
Ivar *ivarList = bIsSelfClass ? class_copyIvarList([cls class], &iVarCount) : NULL;/*变量列表，含属性以及私有变量*/   \
objc_property_t *propList = bIsSelfClass ? NULL : class_copyPropertyList(cls, &propVarCount);/*属性列表*/   \
sharedVarCount = bIsSelfClass ? iVarCount : propVarCount;   \
\
for (int i = 0; i < sharedVarCount; i++) {  \
const char *varName = bIsSelfClass ? ivar_getName(*(ivarList + i)) : property_getName(*(propList + i)); \
NSString *key = [NSString stringWithUTF8String:varName];   \
id varValue = [coder decodeObjectForKey:key];   \
NSArray *filters = @[@"superclass", @"description", @"debugDescription", @"hash"]; \
if (varValue && [filters containsObject:key] == NO) { \
[self setValue:varValue forKey:key];    \
}   \
}   \
free(ivarList); \
free(propList); \
cls = class_getSuperclass(cls); \
}   \
return self;    \
}   \
\
- (void)encodeWithCoder:(NSCoder *)coder    \
{   \
NSLog(@"%s",__func__);  \
Class cls = [self class];   \
while (cls != [NSObject class]) {   \
/*判断是自身类还是父类*/    \
BOOL bIsSelfClass = (cls == [self class]);  \
unsigned int iVarCount = 0; \
unsigned int propVarCount = 0;  \
unsigned int sharedVarCount = 0;    \
Ivar *ivarList = bIsSelfClass ? class_copyIvarList([cls class], &iVarCount) : NULL;/*变量列表，含属性以及私有变量*/   \
objc_property_t *propList = bIsSelfClass ? NULL : class_copyPropertyList(cls, &propVarCount);/*属性列表*/ \
sharedVarCount = bIsSelfClass ? iVarCount : propVarCount;   \
\
for (int i = 0; i < sharedVarCount; i++) {  \
const char *varName = bIsSelfClass ? ivar_getName(*(ivarList + i)) : property_getName(*(propList + i)); \
NSString *key = [NSString stringWithUTF8String:varName];    \
/*valueForKey只能获取本类所有变量以及所有层级父类的属性，不包含任何父类的私有变量(会崩溃)*/  \
id varValue = [self valueForKey:key];   \
NSArray *filters = @[@"superclass", @"description", @"debugDescription", @"hash"]; \
if (varValue && [filters containsObject:key] == NO) { \
[coder encodeObject:varValue forKey:key];   \
}   \
}   \
free(ivarList); \
free(propList); \
cls = class_getSuperclass(cls); \
}   \
}


#define TRYHONE_COPY_WITH_ZONE()  \
\
/*如果不实现copyWithZone:方法，则[personObject copy]时会崩溃*/   \
- (id)copyWithZone:(NSZone *)zone   \
{   \
NSLog(@"%s",__func__);  \
id copy = [[[self class] allocWithZone:zone] init];    \
Class cls = [self class];   \
while (cls != [NSObject class]) {  \
/*判断是自身类还是父类*/    \
BOOL bIsSelfClass = (cls == [self class]);  \
unsigned int iVarCount = 0; \
unsigned int propVarCount = 0;  \
unsigned int sharedVarCount = 0;    \
Ivar *ivarList = bIsSelfClass ? class_copyIvarList([cls class], &iVarCount) : NULL;/*变量列表，含属性以及私有变量*/   \
objc_property_t *propList = bIsSelfClass ? NULL : class_copyPropertyList(cls, &propVarCount);/*属性列表*/   \
sharedVarCount = bIsSelfClass ? iVarCount : propVarCount;   \
\
for (int i = 0; i < sharedVarCount; i++) {  \
const char *varName = bIsSelfClass ? ivar_getName(*(ivarList + i)) : property_getName(*(propList + i)); \
NSString *key = [NSString stringWithUTF8String:varName];    \
/*valueForKey只能获取本类所有变量以及所有层级父类的属性，不包含任何父类的私有变量(会崩溃)*/  \
id varValue = [self valueForKey:key];   \
NSArray *filters = @[@"superclass", @"description", @"debugDescription", @"hash"]; \
if (varValue && [filters containsObject:key] == NO) { \
[copy setValue:varValue forKey:key];    \
}   \
}   \
free(ivarList); \
free(propList); \
cls = class_getSuperclass(cls); \
}   \
return copy;    \
}


#define TRYHONE_DESCRIPTION() \
\
/* 用来打印本类的所有变量(成员变量+属性变量)，所有层级父类的属性变量及其对应的值 */  \
- (NSString *)description   \
{   \
NSString  *despStr = @"";   \
Class cls = [self class];   \
while (cls != [NSObject class]) {   \
/*判断是自身类还是父类*/  \
BOOL bIsSelfClass = (cls == [self class]);  \
unsigned int iVarCount = 0; \
unsigned int propVarCount = 0;  \
unsigned int sharedVarCount = 0;    \
Ivar *ivarList = bIsSelfClass ? class_copyIvarList([cls class], &iVarCount) : NULL;/*变量列表，含属性以及私有变量*/   \
objc_property_t *propList = bIsSelfClass ? NULL : class_copyPropertyList(cls, &propVarCount);/*属性列表*/   \
sharedVarCount = bIsSelfClass ? iVarCount : propVarCount;   \
\
for (int i = 0; i < sharedVarCount; i++) {  \
const char *varName = bIsSelfClass ? ivar_getName(*(ivarList + i)) : property_getName(*(propList + i)); \
NSString *key = [NSString stringWithUTF8String:varName];    \
/*valueForKey只能获取本类所有变量以及所有层级父类的属性，不包含任何父类的私有变量(会崩溃)*/  \
id varValue = [self valueForKey:key];   \
NSArray *filters = @[@"superclass", @"description", @"debugDescription", @"hash"]; \
if (varValue && [filters containsObject:key] == NO) { \
despStr = [despStr stringByAppendingString:[NSString stringWithFormat:@"%@: %@\n", key, varValue]]; \
}   \
}   \
free(ivarList); \
free(propList); \
cls = class_getSuperclass(cls); \
}   \
return despStr; \
}

/* 封装归档keyedArchiver操作 同一个方法快内只能出现一次 如需要出现多次 请用{}包含宏使用*/
#define TRYHONE_ARCHIVE(__objToBeArchived__, __key__, __filePath__)    \
\
NSMutableData *TryHone_data = [NSMutableData data]; \
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:TryHone_data];   \
[archiver encodeObject:__objToBeArchived__ forKey:__key__];    \
[archiver finishEncoding];  \
[TryHone_data writeToFile:__filePath__ atomically:YES]


/* 封装反归档keyedUnarchiver操作 同一个方法快内只能出现一次 如需要出现多次 请用{}包含宏使用 */
#define TRYHONE_UNARCHIVE(__objToStoreData__, __key__, __filePath__)   \
NSMutableData *TryHone_dedata = [NSMutableData dataWithContentsOfFile:__filePath__]; \
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:TryHone_dedata];  \
__objToStoreData__ = [unarchiver decodeObjectForKey:__key__];  \
[unarchiver finishDecoding]

#define kDevice_Is_iPhoneX IPHONE_X

#define KNAVFLOAT ({CGFloat kNavFloat = .0; if (kDevice_Is_iPhoneX) { kNavFloat = 24.f;} kNavFloat;})

//自定义宏定义
#define AW_NETWORKCHANGE @"AW_NETWORKCHANGE"
//
#define AW_NETWORK_ERRORRESONE @"AW_NETWORK_ERRORRESONE"




#define IPHONE_X ({BOOL isPhoneX = NO;\
if (@available(iOS 11.0, *)) {\
isPhoneX = [[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom > 0.0;\
}\
(isPhoneX);})


/**
 *导航栏高度
 */
#define SafeAreaTopHeight (IPHONE_X ? 88 : 64)

/**
 *tabbar高度
 */
#define SafeAreaBottomHeight (IPHONE_X ? (49 + 34) : 49)
#define StatusBarHeight         (kDevice_Is_iPhoneX ? 44.f : 20.f)
#define NavBarHeight            (kDevice_Is_iPhoneX ? 88.f : 64.f)
#define BottomSafeHeight        (kDevice_Is_iPhoneX ? 34 : 0)
#define NavBarAndBottomHeight   (kDevice_Is_iPhoneX ? 122.f : 64.f)

//语言本地化
#define AppLanguage @"appLanguage"

//有版本更新
#define JFAPPUPDATEINFO @"JFAPPUPDATEINFO_AW"

//颜色
#define RGB(r,g,b) [UIColor colorWithRed:r / 255.0 green:g / 255.0 blue:b / 255.0 alpha:1.0]
#define HexColor(str) [UIColor colorWithHexString:str]

//#define CustomLocalizedString(key, comment) \
[[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults] objectForKey:@"appLanguage"]] ofType:@"lproj"]] localizedStringForKey:(key) value:@"" table:nil]

#ifndef IS_IOS_VERSION_LESS_THAN
#define IS_IOS_VERSION_LESS_THAN(versionString)  \
([[[UIDevice currentDevice] systemVersion] compare:(versionString) options:NSNumericSearch] == NSOrderedAscending)
#endif


#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)


#define SuppressPerformSelectorLeakWarning(Stuff) \
do { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
Stuff; \
_Pragma("clang diagnostic pop") \
} while (0)


#define AWPString(s)    @property(nonatomic,copy) NSString * s;
#define AWPInteger(s)   @property(nonatomic,assign) NSInteger s;
#define AWPFloat(s)     @property(nonatomic,assign) CGFloat s;
#define AWPLong(s)      @property(nonatomic,assign) long s;
#define AWPDict(s)      @property(nonatomic,copy) NSDictionary * s;
#define AWPMutDict(s)   @property(nonatomic,strong) NSMutableDictionary * s;
#define AWPArray(s)     @property(nonatomic,copy)   NSArray * s;
#define AWPMutArray(s)  @property(nonatomic,strong) NSMutableArray * s;
#define AWPBool(s)      @property(nonatomic,assign) BOOL s;
//UIKit
#define AWPButton(s)    @property(nonatomic,strong) UIButton * s;
#define AWPView(s)      @property(nonatomic,strong) UIView * s;
#define AWPTextField(s) @property(nonatomic,strong) UITextField * s;
#define AWPTextView(s)  @property(nonatomic,strong) UITextView * s;
#define AWPTableView(s) @property(nonatomic,strong) UITableView * s;
#define AWPImageView(s) @property(nonatomic,strong) UIImageView * s;
#define AWPLable(s)     @property(nonatomic,strong) UILabel * s;
//自定义
#define AWPCusObject(type,s)     @property(nonatomic,strong) type * s;

//简化Mason
#define AWMasLeft(view,value)  { make.left.mas_equalTo(view).offset(value);}
#define AWMasRight(view,value)  { make.right.mas_equalTo(view).offset(value);}
#define AWMasTop(view,value)  { make.top.mas_equalTo(view).offset(value);}
#define AWMasBottom(view,value)  { make.bottom.mas_equalTo(view).offset(value);}
#define AWMasCenterX(view,value)  { make.centerX.mas_equalTo(view).offset(value);}
#define AWMasCenterY(view,value)  { make.centerY.mas_equalTo(view).offset(value);}
#define AWMasCenter(view)         { make.center.mas_equalTo(view);}
#define AWMasWidth(value)         {make.width.mas_equalTo(value);}
#define AWMasHeight(value)         {make.height.mas_equalTo(value);}

#define AWMasFast(view,block)           \
[view mas_makeConstraints:^(MASConstraintMaker *make) {  \
      block;                                             \
}];                                                      \

#define AWMasRemakeFast(view,block)           \
[view mas_remakeConstraints:^(MASConstraintMaker *make) {  \
      block;                                               \
}];                                                        \

#define AWAddSubView(father,view)     [father addSubview:view];
#define AWAddSelfSubView(view)     [self addSubview:view];
#define AWAddCellSubView(view)     [self.contentView addSubview:view];


#define AWLazyGetMethodWithBlock(type, attribute,block)      \
- (type *)attribute                                 \
{                                                   \
    if (!_##attribute) {                            \
        type * tempObject = [[type alloc] init];    \
        {                                           \
            block;                                  \
        }                                           \
        _##attribute = tempObject;                  \
    }                                               \
    return _##attribute;                            \
}

#define AWLazyGetMethod(type, attribute)            \
- (type *)attribute                                 \
{                                                   \
    if (!_##attribute) {                            \
        _##attribute = [[type alloc] init];         \
                                                    \
    }                                               \
    return _##attribute;                            \
}


//宏定义实现单例类
#define AWSingleH(name) +(instancetype)share##name;

#define AWSingleM(name) static id _instance;         \
+(instancetype)allocWithZone:(struct _NSZone *)zone  \
{                                                    \
    static dispatch_once_t onceToken;                \
    dispatch_once(&onceToken, ^{                     \
        _instance = [super allocWithZone:zone];      \
    });                                              \
    return _instance;                                \
}                                                    \
                                                     \
+(instancetype)share##name                           \
{                                                    \
    return [[self alloc]init];                       \
}                                                    \
-(id)copyWithZone:(NSZone *)zone                     \
{                                                    \
    return _instance;                                \
}                                                    \
-(id)mutableCopyWithZone:(NSZone *)zone              \
{                                                    \
    return _instance;                                \
}                                                    \


